#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QStringList>
#include <QRadioButton>
#include <QFrame>
#include "Keyboard.h"

Keyboard::Keyboard(QObject *parent) :
        QObject(parent),
        mBasicKeyboard(NULL),
        mScientificKeyboard(NULL),
        mPogramKeyboard(NULL),
        mBasicKeyboardButtongroup(NULL),
        mScientificKeyboardButtongroup(NULL),
        mProgramKeyboardButtongroup(NULL),
        mStatisticsKeyboardButtongroup(NULL),
        mHexButtonGroup(NULL)
{
    mBasicKeyboardButtongroup = new QButtonGroup(this);
    mScientificKeyboardButtongroup = new QButtonGroup(this);
    mProgramKeyboardButtongroup = new QButtonGroup(this);
    mStatisticsKeyboardButtongroup = new QButtonGroup(this);
    mHexButtonGroup = new QButtonGroup(this);
    mRadixButtonGroup = new QButtonGroup(this);
    invert = false;
}

QWidget* Keyboard::basicKeyboard()
{
    // return created instance
    if(mBasicKeyboard) {
        enableAllButtons();
        return mBasicKeyboard;
    }
    // create if not yet created
    mBasicKeyboard = new QWidget;
    QVBoxLayout* vLayout = new QVBoxLayout;
    vLayout->setDirection(QVBoxLayout::BottomToTop);
    // each row for keyboard is created by passing the text of each button as a string delimited by comma.
    QHBoxLayout* row1 = createButtonRow("M+,0,+-,.,+,=",mBasicKeyboardButtongroup);
    vLayout->addLayout(row1);
    QHBoxLayout* row2 = createButtonRow("M-,1,2,3,-,1/X",mBasicKeyboardButtongroup);
    vLayout->addLayout(row2);
    QHBoxLayout* row3 = createButtonRow("MS,4,5,6,*,%",mBasicKeyboardButtongroup);
    vLayout->addLayout(row3);
    QHBoxLayout* row4 = createButtonRow("MR,7,8,9,/,sqrt",mBasicKeyboardButtongroup);
    vLayout->addLayout(row4);
    QHBoxLayout* row5 = createButtonRow("MC,BackSpace,CE,Clear",mBasicKeyboardButtongroup);
    vLayout->addLayout(row5);
    mBasicKeyboard->setLayout(vLayout);

    return mBasicKeyboard;
}

QButtonGroup* Keyboard::basicKeyboardButtongroup()
{
    return mBasicKeyboardButtongroup;
}

QWidget* Keyboard::scientificKeyboard()
{
    // dont create if it is already created.
    if(mScientificKeyboard)
    {
        enableAllButtons();
        return mScientificKeyboard;
    }
    mScientificKeyboard = new QWidget;
    QVBoxLayout* vLayout = new QVBoxLayout(mScientificKeyboard);
    vLayout->setDirection(QVBoxLayout::BottomToTop);
    // each row for keyboard is created by passing the text of each button as a string delimited by comma.
    QHBoxLayout* row1 = createButtonRow("F-E,Exp,Mod,log,10^x",mScientificKeyboardButtongroup);
    vLayout->addLayout(row1);
    QHBoxLayout* row2 = createButtonRow("Pie,tanh,tan,x^3,cuberoot",mScientificKeyboardButtongroup);
    vLayout->addLayout(row2);
    QHBoxLayout* row3 = createButtonRow("dms,cosh,cos,x^y,yrootx",mScientificKeyboardButtongroup);
    vLayout->addLayout(row3);
    QHBoxLayout* row4 = createButtonRow("Int,sinh,sin,x^2,n!",mScientificKeyboardButtongroup);
    vLayout->addLayout(row4);
    QHBoxLayout* row5 = createButtonRow("ln",mScientificKeyboardButtongroup);
    mInvButton = createButton("Inv");
    row5->insertWidget(0,mInvButton);
    connect(mInvButton,SIGNAL(clicked()),this,SLOT(handleInvClicked()),Qt::UniqueConnection);
    QPushButton* openBrace = createButton("(");
    QPushButton* closeBrace = createButton(")");
    connect(openBrace,SIGNAL(clicked()),this,SIGNAL(openBraceClicked()),Qt::UniqueConnection);
    connect(closeBrace,SIGNAL(clicked()),this,SIGNAL(closeBraceClicked()),Qt::UniqueConnection);
    row5->addWidget(openBrace);
    row5->addWidget(closeBrace);
    mBraceCounterButton = createButton("");
    mBraceCounterButton->setEnabled(false);
    mBraceCounterButton->setFixedWidth(40);
    row5->insertWidget(0,mBraceCounterButton);
    vLayout->addLayout(row5);
    QRadioButton* degrees = new QRadioButton("Degrees");
    QRadioButton* radians = new QRadioButton("Radians");
    radians->click();
    QRadioButton* grads = new QRadioButton("Grads");
    QHBoxLayout* row6 = new QHBoxLayout;
    row6->addWidget(degrees);
    row6->addWidget(radians);
    row6->addWidget(grads);
    connect(degrees,SIGNAL(clicked()),this,SIGNAL(degreesClicked()));
    connect(radians,SIGNAL(clicked()),this,SIGNAL(radiansClicked()));
    connect(grads,SIGNAL(clicked()),this,SIGNAL(gradsClicked()));
    vLayout->addLayout(row6);
    mScientificKeyboard->setLayout(vLayout);
    handleBinButtons(true);
    return mScientificKeyboard;
}

QButtonGroup* Keyboard::scientificKeyboardButtongroup()
{
    return mScientificKeyboardButtongroup;
}

QWidget* Keyboard::programKeyboard()
{
    if(mPogramKeyboard)
    {
        QAbstractButton* checkedButton = mRadixButtonGroup->checkedButton();
        if(checkedButton) {
            radixButtonClicked(checkedButton);
            return mPogramKeyboard;
        }
   }
    mPogramKeyboard = new QWidget;
    // This is the layout for buttons
    QVBoxLayout* vLayout = new QVBoxLayout;
    vLayout->setDirection(QVBoxLayout::BottomToTop);
    // each row for keyboard is created by passing the text of each button as a string delimited by comma.
    QHBoxLayout* row1 = createButtonRow("Not,And",mProgramKeyboardButtongroup);
    vLayout->addLayout(row1);
    QHBoxLayout* row2 = createButtonRow("Lsh,Rsh",mProgramKeyboardButtongroup);
    vLayout->addLayout(row2);
    QHBoxLayout* row3 = createButtonRow("Or,Xor",mProgramKeyboardButtongroup);
    vLayout->addLayout(row3);
    QHBoxLayout* row4 = createButtonRow("RoL,RoR",mProgramKeyboardButtongroup);
    vLayout->addLayout(row4);
    QHBoxLayout* row5 = new QHBoxLayout;//createButtonRow("",mProgramKeyboardButtongroup);
    QPushButton* openBrace = createButton("(");
    QPushButton* closeBrace = createButton(")");
    connect(openBrace,SIGNAL(clicked()),this,SIGNAL(openBraceClicked()),Qt::UniqueConnection);
    connect(closeBrace,SIGNAL(clicked()),this,SIGNAL(closeBraceClicked()),Qt::UniqueConnection);
    row5->addWidget(openBrace);
    row5->addWidget(closeBrace);
    vLayout->addLayout(row5);
    QHBoxLayout* row6 = createButtonRow("Mod",mProgramKeyboardButtongroup);
    //vLayout->addLayout(row6);
    mBraceCounterButton = createButton("");
    mBraceCounterButton->setEnabled(false);
    mBraceCounterButton->setFixedWidth(40);
    row6->insertWidget(0,mBraceCounterButton);
    vLayout->addLayout(row6);
    QVBoxLayout* hexButtonColumn = createButtonColumn("A,B,C,D,E,F",mHexButtonGroup);
    connect(mHexButtonGroup,SIGNAL(buttonClicked(QAbstractButton*)),
            this,SIGNAL(hexButtonClicked(QAbstractButton*)),Qt::UniqueConnection);
    // This is the layout for radio buttons
    QVBoxLayout* radioButtonsVLayout1 = new QVBoxLayout;
    QRadioButton* byte = new QRadioButton("Byte");
    QRadioButton* word = new QRadioButton("Word");
    QRadioButton* dword = new QRadioButton("DWord");
    QRadioButton* qword = new QRadioButton("Qword");
    qword->click();
    connect(byte,SIGNAL(clicked()),this,SIGNAL(byteClicked()),Qt::UniqueConnection);
    connect(word,SIGNAL(clicked()),this,SIGNAL(wordClicked()),Qt::UniqueConnection);
    connect(dword,SIGNAL(clicked()),this,SIGNAL(dwordClicked()),Qt::UniqueConnection);
    connect(qword,SIGNAL(clicked()),this,SIGNAL(qwordClicked()),Qt::UniqueConnection);
    radioButtonsVLayout1->addWidget(qword);
    radioButtonsVLayout1->addWidget(dword);
    radioButtonsVLayout1->addWidget(word);
    radioButtonsVLayout1->addWidget(byte);
    QFrame* radioButtonFrame1 = new QFrame;
    radioButtonFrame1->setLayout(radioButtonsVLayout1);
    QVBoxLayout* radioButtonsVLayout2 = createButtonColumn("Bin,Oct,Dec,Hex",mRadixButtonGroup,true);
    handleHexButtons(false);
    handleOctButtons(true);
    connect(mRadixButtonGroup,SIGNAL(buttonClicked(QAbstractButton*)),
            this,SLOT(radixButtonClicked(QAbstractButton*)),Qt::UniqueConnection);
    QFrame* radioButtonFrame2 = new QFrame;
    radioButtonFrame2->setLayout(radioButtonsVLayout2);
    QVBoxLayout* radioButtonsVLayout = new QVBoxLayout;
    radioButtonsVLayout->addWidget(radioButtonFrame2);
    radioButtonsVLayout->addWidget(radioButtonFrame1);
    QHBoxLayout* prgmodeMainLayout = new QHBoxLayout;
    prgmodeMainLayout->addLayout(radioButtonsVLayout);
    prgmodeMainLayout->addLayout(vLayout);
    prgmodeMainLayout->addLayout(hexButtonColumn);
    mPogramKeyboard->setLayout(prgmodeMainLayout);
    return mPogramKeyboard;
}

QButtonGroup* Keyboard::programKeyboardButtongroup()
{
    return mProgramKeyboardButtongroup;
}

QWidget* Keyboard::statisticsKeyboard()
{
    if(mStatisticsKeyboard) {
        return mStatisticsKeyboard;
    }
    mStatisticsKeyboard = new QWidget;
    QVBoxLayout* statisticsLayout = new QVBoxLayout;
    statisticsLayout->setDirection(QVBoxLayout::BottomToTop);
    // each row for keyboard is created by passing the text of each button as a string delimited by comma.
    QHBoxLayout* row1 = createButtonRow("0,.,+-,Add",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row1);
    QHBoxLayout* row2 = createButtonRow("1,2,3,sn,sn-1",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row2);
    QHBoxLayout* row3 = createButtonRow("4,5,6,sx,sx^2",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row3);
    QHBoxLayout* row4 = createButtonRow("7,8,9,sdx,sdx^2",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row4);
    QHBoxLayout* row5 = createButtonRow("BackSpace,CAD,Clear,F-E,Exp",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row5);
    QHBoxLayout* row6 = createButtonRow("MC,MR,MS,M+,M-",mStatisticsKeyboardButtongroup);
    statisticsLayout->addLayout(row6);
    mStatisticsKeyboard->setLayout(statisticsLayout);

    return mStatisticsKeyboard;
}

QButtonGroup* Keyboard::statisticsKeyboardButtongroup()
{
    return mStatisticsKeyboardButtongroup;
}

QPushButton* Keyboard::createButton(QString buttonText,QWidget* parent)
{
    QPushButton* button = new QPushButton(buttonText,parent);
    return button;
}

QHBoxLayout* Keyboard::createButtonRow(QString buttonTexts,QButtonGroup* buttonGroup)
{
    // this is the layout to hold all the buttons created.
    QHBoxLayout* layout = new QHBoxLayout;
    // Split the string so that we get all button's text as a list
    QStringList buttonTextList = buttonTexts.split(",");
    // go through each button text and create a pushbutton with that text.
    for(int i=0;i<buttonTextList.count();i++)
    {
        QPushButton* button = new QPushButton(buttonTextList[i]);
        // add this button to button group so that we know when a button is clicked.
        buttonGroup->addButton(button);
        layout->addWidget(button);
    }
    return layout;
}

QVBoxLayout* Keyboard::createButtonColumn(QString buttonTexts,QButtonGroup* buttonGroup,bool isRadioButton)
{
    // this is the layout to hold all the buttons created.
    QVBoxLayout* layout = new QVBoxLayout;
    // Split the string so that we get all button's text as a list
    QStringList buttonTextList = buttonTexts.split(",");
    // go through each button text and create a pushbutton with that text.
    for(int i=0;i<buttonTextList.count();i++)
    {
        QAbstractButton* button;
        if(isRadioButton) {
            button = new QRadioButton(buttonTextList[i]);
            QString str= button->text();
            if(str=="Dec")
            {
               button->setChecked(true);
            }
        }
        else {
            button = new QPushButton(buttonTextList[i]);
        }
        // add this button to button group so that we know when a button is clicked.
        buttonGroup->addButton(button);
        layout->addWidget(button);
    }
    return layout;
}

QPushButton* Keyboard::braceCounterButton()
{
    return mBraceCounterButton;
}

void Keyboard::setBraceCounterText(QString text)
{
    if(mBraceCounterButton) {
        mBraceCounterButton->setText(text);
    }
}
//void Keyboard::hexButtonClicked(QAbstractButton *button)
//{
//    emit alphabetsClicked();
//}

// this will handle which buttons should disabled when a particular radix is selected.
// for ex, when Oct radix is selected, buttons 8,9 will be disabled
void Keyboard::radixButtonClicked(QAbstractButton* button)
{
    handleHexButtons(false);
    handleOctButtons(true);
    handleBinButtons(true);
   // handleDecButtons(true);

    if("Hex" == button->text()) {
        handleHexButtons(button->isChecked());
        if(button->isChecked())
            emit hexClicked();
    }
    else if("Oct" == button->text()){
        handleOctButtons(!button->isChecked());
        if(button->isChecked())
            emit octClicked();
    }
    else if("Bin" == button->text()){
        handleBinButtons(!button->isChecked());
        if(button->isChecked())
            emit binClicked();
    }
    else if("Dec" == button->text()){
       // handleDecButtons(!button->isChecked());
        //if(button->isChecked())
            emit decClicked();
    }
}

void Keyboard::handleHexButtons(bool checked)
{
    if(mHexButtonGroup) {
        QList<QAbstractButton*> buttons = mHexButtonGroup->buttons();
        for(int i=0;i<buttons.count();++i) {
            buttons.at(i)->setEnabled(checked);
        }
    }
}

void Keyboard::handleOctButtons(bool checked)
{
    if(mProgramKeyboardButtongroup)
    {
        QList<QAbstractButton*> buttons = basicKeyboardButtongroup()->buttons();
        for(int i=0;i<buttons.count();++i) {
            if("8" == buttons.at(i)->text() || "9" == buttons.at(i)->text())
                buttons.at(i)->setEnabled(checked);
        }
    }
    else{
        handleOctButtons(true);
    }
}

void Keyboard::handleBinButtons(bool checked)
{
    if(mBasicKeyboardButtongroup)
    {
        QList<QAbstractButton*> buttons = basicKeyboardButtongroup()->buttons();
        for(int i=0;i<buttons.count();++i) {
            if("2" == buttons.at(i)->text()|| "3" == buttons.at(i)->text()||"4" == buttons.at(i)->text()||
               "5" == buttons.at(i)->text()|| "6" == buttons.at(i)->text()||"7" == buttons.at(i)->text()||
               "8" == buttons.at(i)->text()|| "9" == buttons.at(i)->text())
                buttons.at(i)->setEnabled(checked);
        }
    }
    else{
        handleBinButtons(true);
    }
}
//void Keyboard::handleDecButtons(bool checked)
//{

//}
void Keyboard::enableAllButtons() {
    handleHexButtons(true);
    handleOctButtons(true);
    handleBinButtons(true);
}

void Keyboard::handleInvClicked()
{
    invert = !invert;
    QList<QAbstractButton*> buttons = scientificKeyboardButtongroup()->buttons();
    if(invert)
    {
        for(int i=0;i<buttons.count();i++)
        {
            if("sin" == buttons.at(i)->text())
            {
                buttons.at(i)->setText("asin");
            }
            else if("cos"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("acos");
            }
            else if("tan"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("atan");
            }
            else if("sinh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("asinh");
            }
            else if("cosh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("acosh");
            }
            else if("tanh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("atanh");
            }
            else if("ln"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("epowx");
            }
            else if("dms"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("deg");
            }
            else if("Pie"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("2Pie");
            }
            else if("Int"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("Frac");
            }
        }
    }
    else
    {
        for(int i=0;i<buttons.count();i++)
        {
            if("asin" == buttons.at(i)->text())
            {
                buttons.at(i)->setText("sin");
            }
            else if("acos"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("cos");
            }
            else if("atan"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("tan");
            }
            else if("asinh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("sinh");
            }
            else if("acosh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("cosh");
            }
            else if("atanh"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("tanh");
            }
            else if("epowx"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("ln");
            }
            else if("deg"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("dms");
            }
            else if("2Pie"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("Pie");
            }
            else if("Frac"==buttons.at(i)->text())
            {
                buttons.at(i)->setText("Int");
            }
        }
    }
}
